package com.codemonkey.lq.qd.facotry.support;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.SqlSessionFactory;

import com.codemonkey.lq.qd.ServiceContext;
import com.codemonkey.lq.qd.db.impl.MyBatisDaoImpl;
import com.codemonkey.lq.qd.facotry.config.AbstractActionDefinition;
import com.codemonkey.lq.qd.facotry.config.ExecuteEventMulticaster;
import com.codemonkey.lq.qd.facotry.config.ExecutionEvent;
import com.codemonkey.lq.qd.facotry.config.ServiceDefinition;
import com.codemonkey.lq.qd.facotry.config.SqlSessionFactorySelecter;
import com.codemonkey.lq.qd.facotry.config.event.ExecutionEventObjectFactory;
import com.codemonkey.lq.qd.facotry.config.event.SimpleExecuteEventMulticaster;
import com.codemonkey.lq.qd.utils.ExpressionEvaluatorUtils;
import com.codemonkey.lq.qd.utils.StringHelper;

/**
 * 本类所处的package直接仿造spring-beans中的GenericBeanDefinition
 * 用于处理没有<flow-list>的Service
 * @author LQ
 *
 */
public class GenericActionDefinition extends AbstractActionDefinition {

	protected final ExecuteEventMulticaster executeEventMulticaster = SimpleExecuteEventMulticaster.getSingleton();
	protected GenericServiceDefinition parentSD;
	

	public GenericActionDefinition(ServiceDefinition parentSD) {
		super();
		//TODO 这里有问题..
		this.parentSD = ((GenericServiceDefinition)parentSD);
	}

	@Override
	public void execute(ServiceContext serviceContext) throws Exception {
		if (this.getHandler() != null) {
			this.getHandler().preHandle(this, serviceContext);
		}

		String condition = this.getCondition();
		boolean flag = StringHelper.isEmpty(condition) ? true : ExpressionEvaluatorUtils
				.evaluateBoolean(condition, serviceContext.getExecuteContextContainer());

		if (flag) {
			doAction(serviceContext);

			if (this.getHandler() != null) {
				this.getHandler().afterHandle(this, serviceContext);
			}

			ExecutionEvent event =  ExecutionEventObjectFactory.getExecutionEvent(true, this, serviceContext);
			executeEventMulticaster.multicastEvent(event);
		}else{
			// 条件判断失败,不执行
			// 因为action的执行异常时,会将异常上抛给service,所以在action中的false只会是因为条件不满足而不执行
			ExecutionEvent event =  ExecutionEventObjectFactory.getExecutionEvent(false, this, serviceContext);
			executeEventMulticaster.multicastEvent(event);
		}
	}

	protected Object doAction(ServiceContext sc) throws Exception {
		String sqlType = this.getSqlType();

		SqlCommandType commandType = null;
		if (StringHelper.isEmpty(sqlType)) { // TODO 起始,结束 节点,后期改进下,起始结束到底怎么处理
			commandType = SqlCommandType.UNKNOWN;
			return null;
		} else {
			commandType = Enum.valueOf(SqlCommandType.class, sqlType.toUpperCase());
		}

		Object obj = null;
		if (commandType.compareTo(SqlCommandType.SELECT) == 0) {
			obj = selectAction(sc);
		} else if (commandType.compareTo(SqlCommandType.INSERT) == 0) {
			obj = insertAction(sc);
		} else if (commandType.compareTo(SqlCommandType.UPDATE) == 0) {
			obj = updateAction(sc);
		} else if (commandType.compareTo(SqlCommandType.DELETE) == 0) {
			obj = deleteAction(sc);
		} else if (commandType.compareTo(SqlCommandType.UNKNOWN) == 0) {
			//NO THING
		}

		sc.getActionResultContainer().put(this.getResult(), obj);

		return obj;
	}

	@SuppressWarnings("unchecked")
	private Object selectAction(ServiceContext sc) throws Exception {
		Map param = sc.getExecuteContextContainer();

		SqlSessionFactorySelecter selecter = parentSD.getConfiguration()
				.getSqlSessionFactorySelecter();
		SqlSessionFactory sqlSessionFactory = selecter.getSqlSessionFactory(sc, parentSD, this);
		MyBatisDaoImpl myBatisDaoImpl = MyBatisDaoImpl.getDefaultInstance();
		if ("single".equalsIgnoreCase(this.getResultType())) {
			Map map = myBatisDaoImpl.selectOneWithoutCloseSqlSession(parentSD.getSqlSession(sqlSessionFactory),this.getSqlId(), param);
			//			if (result == null || result.equals("")) {
			//				runtimeMap.putAll(map);
			//			} else {
			//				runtimeMap.put(result, map);
			//			}
			return map;
		}

		// "list".equalsIgnoreCase(this.getResultType())
		List<Object> selectList = myBatisDaoImpl.selectListWithoutCloseSqlSession(parentSD.getSqlSession(sqlSessionFactory),this.getSqlId(), param);
		if (selectList != null) {
			return selectList;
		}
		return new ArrayList();

		/*
		String sqlId = StringUtil.empty(actionMap.get("sqlId"));
		String resultType = StringUtil.empty(actionMap.get("resultType"));
		String isPage = StringUtil.empty(actionMap.get("isPage"));
		String result = StringUtil.empty(actionMap.get("result"));

		if (resultType.equals("list")) {
			if (isPage != null && isPage.equals("true")) {
				//分页对象
				Map pageMap = (Map) runtimeMap.get("page");
				int currentPage = Integer.parseInt(pageMap.get("currentPage").toString());
				Object objPageSize = pageMap.get("pageSize");
				int pageSize = PageParameter.DEFAULT_PAGE_SIZE;
				if (objPageSize != null) {
					pageSize = Integer.parseInt(objPageSize.toString());
				}

				List list = new ArrayList();
				Map totalRecordMap = coreDao.selectOne(sqlId + "_Count", param);
				int totalCount = Integer.parseInt(totalRecordMap.get("TOTAL").toString());

				PageParameter pageParameter = new PageParameter();
				pageParameter.setPageSize(pageSize);
				pageParameter.setTotalCount(totalCount);
				pageParameter.setCurrentPage(currentPage);

				pageMap.put("pageSize", pageParameter.getPageSize());
				pageMap.put("prePage", pageParameter.getPrePage());
				pageMap.put("nextPage", pageParameter.getNextPage());
				pageMap.put("totalPage", pageParameter.getTotalPage());
				pageMap.put("totalCount", pageParameter.getTotalCount());
				pageMap.put("startIndex", pageParameter.getStartIndex());
				pageMap.put("endIndex", pageParameter.getEndIndex());
				runtimeMap.put("page", pageMap);

				if (totalCount > 0) {
					list = coreDao.selectListByPage(sqlId, param, pageParameter);
				}
				runtimeMap.put("total", totalCount);
				if (result == null || result.equals("result")) {
					runtimeMap.put("rows", list);
				} else {
					runtimeMap.put(result, list);
				}

				return list;
			} else {
				List list = coreDao.selectList(sqlId, param);
				if (result == null || result.equals("result")) {
					runtimeMap.put("rows", list);
				} else {
					runtimeMap.put(result, list);
				}
				return list;
			}
		} else {
			Map map = coreDao.selectOne(sqlId, param);
			if (result == null || result.equals("")) {
				runtimeMap.putAll(map);
			} else {
				runtimeMap.put(result, map);
			}
			return map;
		}
		*/
	}

	private Object insertAction(ServiceContext sc) throws Exception {
		Map param = sc.getExecuteContextContainer();

		SqlSessionFactorySelecter selecter = parentSD.getConfiguration()
				.getSqlSessionFactorySelecter();
		SqlSessionFactory sqlSessionFactory = selecter.getSqlSessionFactory(sc, parentSD, this);
		MyBatisDaoImpl myBatisDaoImpl = MyBatisDaoImpl.getDefaultInstance();

		int cnt = myBatisDaoImpl.insertWithoutCloseSqlSession(parentSD.getSqlSession(sqlSessionFactory),this.getSqlId(), param);
		return cnt;
	}

	private Object updateAction(ServiceContext sc) throws Exception {
		Map param = sc.getExecuteContextContainer();

		SqlSessionFactorySelecter selecter = parentSD.getConfiguration()
				.getSqlSessionFactorySelecter();
		SqlSessionFactory sqlSessionFactory = selecter.getSqlSessionFactory(sc, parentSD, this);
		MyBatisDaoImpl myBatisDaoImpl = MyBatisDaoImpl.getDefaultInstance();

		int cnt = myBatisDaoImpl.updateWithoutCloseSqlSession(parentSD.getSqlSession(sqlSessionFactory),this.getSqlId(), param);
		return cnt;
	}

	private Object deleteAction(ServiceContext sc) throws Exception {
		Map param = sc.getExecuteContextContainer();

		SqlSessionFactorySelecter selecter = parentSD.getConfiguration()
				.getSqlSessionFactorySelecter();
		SqlSessionFactory sqlSessionFactory = selecter.getSqlSessionFactory(sc, parentSD, this);
		MyBatisDaoImpl myBatisDaoImpl = MyBatisDaoImpl.getDefaultInstance();

		int cnt = myBatisDaoImpl.deleteWithoutCloseSqlSession(parentSD.getSqlSession(sqlSessionFactory),this.getSqlId(), param);
		return cnt;
	}

	/**/

	public GenericServiceDefinition getParentSD() {
		return parentSD;
	}

	public void setParentSD(GenericServiceDefinition parentSD) {
		this.parentSD = parentSD;
	}

}
